package com.vains.io;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.EnumMap;

/**
 * 二维码生成工具
 * @author vains
 */
@Slf4j
public class QrCodeUtils {

    private QrCodeUtils() {}

    /**
     * 生成一个二维码
     * @param text 二维码内容
     * @param width 二维码宽度
     * @param height 二维码高度
     * @return 返回页面可以直接显示的base64编码之后的字符串
     */
    public static String getQrCode(String text, int width, int height) {
        BitMatrix bitMatrix = getBitMatrix(text, width, height);
        if (bitMatrix == null) {
            return null;
        }
        ByteArrayOutputStream pngOutputStream = new ByteArrayOutputStream();
        try {
            MatrixToImageWriter.writeToStream(bitMatrix, "PNG", pngOutputStream);
        } catch (IOException e) {
            log.error("二维码转byte数组失败, 原因：", e);
        }
        return "data:image/png;base64," + Base64.encodeBase64String(pngOutputStream.toByteArray());
    }

    /**
     * 生成一个二维码对象
     *  当传入text为空时不会生成
     * @param text 二维码内容
     * @param width 二维码宽度
     * @param height 二维码高度
     * @return 返回表示Bit的2D矩阵对象
     */
    public static BitMatrix getBitMatrix(String text, int width, int height) {
        if (StringUtils.isBlank(text)) {
            log.error("二维码生成失败: 二维码内容为空!");
            return null;
        }
        EnumMap<EncodeHintType, Object> hints = new EnumMap<>(EncodeHintType.class);
        hints.put(EncodeHintType.AZTEC_LAYERS, "2");
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, StandardCharsets.UTF_8);
        hints.put(EncodeHintType.MARGIN, 1);
        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        try {
            return qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height, hints);
        } catch (WriterException e) {
            log.error("二维码生成失败，原因：", e);
            return null;
        }
    }

    /**
     * 生成二维码图片到磁盘
     *  当传入二维码内容为空时,不会生成
     * @param text 二维码内容
     * @param width 宽度
     * @param height 高度
     * @param path 生成路径(包括文件名)
     * @return 返回生成图片的名称
     *              返回 null 代表生成失败
     */
    public static String getQrCodeImage(String text, int width, int height, String path) {
        BitMatrix bitMatrix = getBitMatrix(text, width, height);
        if (bitMatrix == null) {
            return null;
        }
        File file=new File(path);
        try {
            if (!file.exists() && file.createNewFile()) {
                OutputStream ous = new FileOutputStream(file);
                MatrixToImageWriter.writeToStream(bitMatrix, "PNG", ous);
            }
        } catch (IOException e) {
            log.error("二维码生成失败, 原因：", e);
            return null;
        }
        return file.getName();
    }

    public static void main(String[] args) {
        System.out.println(getQrCode("测试", 200, 200));
    }

}
